#pragma once

//#include <srs_app_rtsp.hpp>
#include <srs_core.hpp>
#include <srs_app_st.hpp>
#include <srs_app_thread.hpp>
#include <srs_app_listener.hpp>

#include <string>
#include <vector>
#include <map>


#ifdef SRS_AUTO_STREAM_CASTER

class SrsStSocket;
class SrsRtspConn;
class SrsRtspStack;
class SrsRtspCaster;
class SrsConfDirective;
class SrsRtpPacket;
class SrsRequest;
class SrsStSocket;
class SrsRtmpClient;
class SrsRawH264Stream;
class SrsRawAacStream;
struct SrsRawAacStreamCodec;
class SrsSharedPtrMessage;
class SrsCodecSample;
class SrsSimpleBuffer;
class SrsPithyPrint;

/**
* a rtp connection which transport a stream.
*/
class SrsRtpConn: public ISrsUdpHandler {
private:
    SrsPithyPrint* pprint;
    SrsUdpListener* listener;
    SrsRtspConn* rtsp;
    SrsRtpPacket* cache;
    int stream_id;
    int _port;
public:
    SrsRtpConn(SrsRtspConn* r, int p, int sid);
    virtual ~SrsRtpConn();
public:
    virtual int port();
    virtual int listen();
    // interface ISrsUdpHandler
public:
    virtual int on_udp_packet(sockaddr_in* from, char* buf, int nb_buf);
};

/**
* audio is group by frames.
*/
struct SrsRtspAudioCache {
    int64_t dts;
    SrsCodecSample* audio_samples;
    SrsSimpleBuffer* payload;

    SrsRtspAudioCache();
    virtual ~SrsRtspAudioCache();
};

/**
* the time jitter correct for rtsp.
*/
class SrsRtspJitter {
private:
    int64_t previous_timestamp;
    int64_t pts;
    int delta;
public:
    SrsRtspJitter();
    virtual ~SrsRtspJitter();
public:
    virtual int64_t timestamp();
    virtual int correct(int64_t& ts);
};

/**
* the rtsp connection serve the fd.
*/
class SrsRtspConn : public ISrsOneCycleThreadHandler {
private:
    std::string output_template;
    std::string rtsp_tcUrl;
    std::string rtsp_stream;
private:
    std::string session;
    // video stream.
    int video_id;
    std::string video_codec;
    SrsRtpConn* video_rtp;
    // audio stream.
    int audio_id;
    std::string audio_codec;
    int audio_sample_rate;
    int audio_channel;
    SrsRtpConn* audio_rtp;
private:
    st_netfd_t stfd;
    SrsStSocket* skt;
    SrsRtspStack* rtsp;
    SrsRtspCaster* caster;
    SrsOneCycleThread* trd;
private:
    SrsRequest* req;
    SrsStSocket* io;
    SrsRtmpClient* client;
    SrsRtspJitter* vjitter;
    SrsRtspJitter* ajitter;
    int stream_id;
private:
    SrsRawH264Stream* avc;
    std::string h264_sps;
    std::string h264_pps;
private:
    SrsRawAacStream* aac;
    SrsRawAacStreamCodec* acodec;
    std::string aac_specific_config;
    SrsRtspAudioCache* acache;
public:
    SrsRtspConn(SrsRtspCaster* c, st_netfd_t fd, const std::string& o);
    virtual ~SrsRtspConn();
public:
    virtual int serve();
private:
    virtual int do_cycle();
    // internal methods
public:
    virtual int on_rtp_packet(SrsRtpPacket* pkt, int stream_id);
    // interface ISrsOneCycleThreadHandler
public:
    virtual int cycle();
    virtual void on_thread_stop();
private:
    virtual int on_rtp_video(SrsRtpPacket* pkt, int64_t dts, int64_t pts);
    virtual int on_rtp_audio(SrsRtpPacket* pkt, int64_t dts);
    virtual int kickoff_audio_cache(SrsRtpPacket* pkt, int64_t dts);
private:
    virtual int write_sequence_header();
    virtual int write_h264_sps_pps(u_int32_t dts, u_int32_t pts);
    virtual int write_h264_ipb_frame(char* frame, int frame_size, u_int32_t dts, u_int32_t pts);
    virtual int write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, u_int32_t dts);
    virtual int rtmp_write_packet(char type, u_int32_t timestamp, char* data, int size);
private:
    // connect to rtmp output url.
    // @remark ignore when not connected, reconnect when disconnected.
    virtual int connect();
    virtual int connect_app(const std::string& ep_server, const std::string& ep_port);
};

/**
* the caster for rtsp.
*/
class SrsRtspCaster : public ISrsTcpHandler {
private:
    std::string output;
    int local_port_min;
    int local_port_max;
    // key: port, value: whether used.
    std::map<int, bool> used_ports;
private:
    std::vector<SrsRtspConn*> clients;
public:
    SrsRtspCaster(SrsConfDirective* c);
    virtual ~SrsRtspCaster();
public:
    /**
    * alloc a rtp port from local ports pool.
    * @param pport output the rtp port.
    */
    virtual int alloc_port(int* pport);
    /**
    * free the alloced rtp port.
    */
    virtual void free_port(int lpmin, int lpmax);
    // interface ISrsTcpHandler
public:
    virtual int on_tcp_client(st_netfd_t stfd);
    // internal methods.
public:
    virtual void remove(SrsRtspConn* conn);
};

#endif
